package view.bitmap
{
	
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * 显示对象位图化工具。
	 * BitmapProduced是对显示对象的实例进行位图化处理（与BitmapManager不同）
	 * 
	 * @author lipi
	 */
	public class BitmapProduced
	{
		/**
		 * 实时画，REAL_TIME会立即返回
		 */
		public static const REAL_TIME:int = 1;
		
		
		/**
		 * 优先的，PREFERENTIAL会顶掉其他的正在draw的对象
		 */
		public static const PREFERENTIAL:int = 2;
		
		/**
		 * 普通的
		 */
		public static const NORMAL:int = 3;
		
		/**
		 * 最低的保持的帧频，如果程序低于这个帧频draw将不进行
		 */
		public static var minFps:int = 10;
		
		/**
		 *  每次draw的时间相对于每帧运行时间的百分比
		 */
		public static var percentage:Number = 0.5;
		
		public static var appStage:Stage;
		
		
		private static var _instance:BitmapProduced;
		
		/**
		 * 取得BitmapProduced实例
		 */
		public static function getInstance():BitmapProduced
		{
			if(_instance == null)
			{
				_instance = new BitmapProduced();
			}
			return _instance;
		}
		
		/**
		 * @param source 要进行转换的显示对象
		 * @param compFn 完成后的回调函数
		 * @param frameCompFn 第一帧完成的回调函数
		 * @param priority 进行draw的优先级
		 */
		public static function draw(source:DisplayObject,compFn:Function,frameCompFn:Function = null,priority:int = BitmapProduced.NORMAL):void
		{
			var bitmapProduced:BitmapProduced = getInstance();
			bitmapProduced.draw(source,compFn,frameCompFn,priority);
		}
		
		
		//////////////////////////////////////////////////////////////////////
		//
		// 实例
		//
		/////////////////////////////////////////////////////////////////////
		
		private var _compDic:Dictionary;//完成的帧列表
		private var _compFnDic:Dictionary;//所有完成的函数处理
		private var _farmeCompFnDic:Dictionary;//第一帧完成的函数处理
		private var _drawList:Array;//所有进行中的draw列表
		private var _currentFrameDic:Dictionary;//保存显示对象当前进行的帧
		private var _priorityDic:Dictionary;//保存当前显示对象的优先权
		private var _totalFramesDic:Dictionary;//总帧数
		
		private var _limitTime:int = 100;//每帧运行的时间超过这个值draw将不运行,如果当前游戏的的帧频已经很低将无法进行 draw
		private var _drawTime:int = 20;//退出一次draw所用的时间,即每次draw的时间如果多于这个值则中止draw
		private var _frameTime:int = 0;//上一次执行时的时间
		
		
		public function BitmapProduced()
		{
			_limitTime = 1000/minFps;
			_drawTime = 1000/appStage.frameRate*percentage;//_drawTime等于一帧运行的时间乘于一个设定的百分比
			_frameTime = getTimer();
			
			_compDic = new Dictionary();
			_compFnDic = new Dictionary();
			_farmeCompFnDic = new Dictionary();
			_priorityDic = new Dictionary();
			_drawList = [];
			_currentFrameDic = new Dictionary();
			_totalFramesDic = new Dictionary();
			
			appStage.addEventListener(Event.ENTER_FRAME,onEnterFrame);
		}
		
		
		private function onEnterFrame(e:Event):void
		{
			drawHandler();
		}
		
		
		
		/**
		 * @param source 要进行转换的显示对象
		 * @param compFn 完成后的回调函数
		 * @param frameCompFn 第一帧完成的回调函数
		 * @param priority 进行draw的优先级
		 */
		private function draw(source:DisplayObject,compFn:Function,frameCompFn:Function = null,priority:int = BitmapProduced.NORMAL):void
		{
			if(priority == BitmapProduced.REAL_TIME)
			{
				_drawList.unshift(source);
			}else if(priority == BitmapProduced.PREFERENTIAL){
				_drawList.unshift(source);
			}else{
				_drawList.push(source);
			}
			
			
			_compDic[source] = [];
			_compFnDic[source] = compFn;
			_farmeCompFnDic[source] = frameCompFn;
			_currentFrameDic[source] = 0;
			_priorityDic[source] = priority;
			_totalFramesDic[source] = getSourceTotalFrames(source);
			gotoFrame(source,0);
			
			drawHandler(true);
		}
		
		
		
		/**
		 * 进行draw处理
		 * @param newDraw 是否新加入的显示对象，对于新加入的显示对象会进行是否实时处理的判断
		 */
		private function drawHandler(newDraw:Boolean = false):void
		{
			if(_drawList.length == 0) return;
			
			if(newDraw == false)
			{
				var _enterFrameTime:int = getTimer();
				var cFrameSpace:int = _enterFrameTime - _frameTime;
				_frameTime = _enterFrameTime;
			
				if(cFrameSpace > _limitTime) return;//如果当前帧运行时间大于最高帧执行时间则直接跳出
			}else{
				var $source:DisplayObject = _drawList[0];
				if(_priorityDic[$source] != BitmapProduced.REAL_TIME) return;
				
			}
			allHandler();
		}
		
		
		/**
		 * 进行实际画图处理
		 */
		private function allHandler():void
		{
			for(var i:int = 0;i<_drawList.length;i++)
			{
				var $source:DisplayObject = _drawList[i];
				if($source == null) continue;
				var $totalFrames:int = _totalFramesDic[$source];
				var $currentFrame:int = _currentFrameDic[$source];
				
				for(var j:int = $currentFrame;j<$totalFrames;j++)
				{
					(_compDic[$source] as Array).push(drawMovieClip($source));
					gotoFrame($source,j+1);
					_currentFrameDic[$source] = j+1;
					if(j == 0)
					{
						callFn(_farmeCompFnDic[$source],_compDic[$source],_totalFramesDic[$source]);
//						destroy($source);
					}
					
					if(j == $totalFrames-1)
					{
						_drawList[i] = null;
						callFn(_compFnDic[$source],_compDic[$source],_totalFramesDic[$source]);
						destroy($source);
					}
					if(getTimer() - _frameTime > _drawTime)
					{
						return;
					}
				}
			}
			while(_drawList.length > 0 && _drawList[0] == null)
			{
				_drawList.shift();
			}
			
		}
		
		
		
		//调用回调函数
		private function callFn(fn:Function,data:Object,totalFrames:Object):void
		{
			fn((data as Array).concat(),totalFrames);
		}
		
		
		/**
		 * 跳到某一帧,递归跳到某一帧
		 */
		private function gotoFrame(source:DisplayObject,frame:int):void
		{
			if(source is MovieClip)
			{
				if((source as MovieClip).totalFrames > frame)
				{
					(source as MovieClip).gotoAndStop(frame);
				}else{
					(source as MovieClip).gotoAndStop((source as MovieClip).totalFrames);
				}
			}
			
			if(source is DisplayObjectContainer)
			{
				for(var i:int = 0;i<(source as DisplayObjectContainer).numChildren;i++)
				{
					gotoFrame((source as DisplayObjectContainer).getChildAt(i),frame);
				}
			}
		}
		
		
		/**
		 * 取得显示对象的总帧数
		 */
		private function getSourceTotalFrames(source:DisplayObject):int
		{
			var $total:int = 1;
			if(source is MovieClip)
			{
				$total = (source as MovieClip).totalFrames;
			}
			
			if(source is DisplayObjectContainer)
			{
				for(var i:int = 0;i<(source as DisplayObjectContainer).numChildren;i++)
				{
					var $cTotal:int = getSourceTotalFrames((source as DisplayObjectContainer).getChildAt(i));
					if($cTotal > $total)
					{
						$total = $cTotal;
					}
				}
			}
			return $total;
		}
		
		/**
		 * draw出bitmapdata
		 * @param displayObject 需要draw的对象
		 * @return bitmapdata的列表
		 */
		private function drawMovieClip(displayObject:DisplayObject):Array
		{
			var rect:Rectangle = displayObject.getBounds(displayObject);
			/*rect.height = Math.max(rect.height, 3);
			rect.width += 3;*/
			var bitmapData:BitmapData = new BitmapData(rect.width,rect.height,true,0x00FFFFFF);
			bitmapData.draw(displayObject,new Matrix(1,0,0,1,-Math.floor(rect.x),-Math.floor(rect.y)));
			return [bitmapData,new Point(Math.floor(rect.x),Math.floor(rect.y))];
		}
		
		public function destroy(source:*):void
		{
			delete _compDic[source];
			delete _compFnDic[source];
			delete _farmeCompFnDic[source]; 
			delete _currentFrameDic[source]; 
			delete _priorityDic[source];
			delete _totalFramesDic[source]; 
			source = null;
		}
		
	}
}